package com.insa.flopenshop;

import java.util.LinkedList;

public class Verificateur {
	private final Solution solution;
	
	public Verificateur(Solution solution) {
		this.solution = solution;
	}
	
	/**
	 * 
	 * @return true si la solution est valide pour l'instance donnee, false sinon
	 */
	public boolean solutionValide() {
		boolean valid = true;
		int selectedIndex;
		Placement selectedPlacement;
		int numRU = solution.getInstance().getNumRessouceUniversel();
		int numRD = solution.getInstance().getNumRessourceDedie();
		int numT = solution.getInstance().getNumTache(); 
		int[] indexes = new int[numRU];
		int[] nbResDed = new int[numRD];
		int[] nbSousTch = new int[numT];
		for(int i = 0 ; i<numRU ; i++){
			indexes[i]=0;
		}
		for(int i = 0 ; i<numRD ; i++){
			nbResDed[i]=0;
		}
		for(int i = 0 ; i<numT ; i++){
			nbSousTch[i]=0;
		}
			
		// Parcours chronologiquement les placements et verifie que les contraintes sont respectees
		while(valid){
			LinkedList<Placement>[] fileRU = solution.getFileRessourceUniverselle();
			
			// Selectionne le premier index qui n'a pas atteint la fin de la file
			selectedIndex = 0;
			while(
					(selectedIndex < numRU) && (
							(fileRU[selectedIndex].size() == 0) || (
									(fileRU[selectedIndex].size() > 0) && (indexes[selectedIndex] == fileRU[selectedIndex].size())
							)
					)
				){
					selectedIndex++;
			}
			// Fini si tous les index ont atteint la fin de leur liste (ou que la liste etait vide)
			if(selectedIndex == numRU)
				break;
			
			// Recupere l'index de la file avec la date de depart la plus faible et le placement correspondant
			for(int i = 0 ; i<numRU ; i++){
				if(indexes[i] < fileRU[i].size()){
					if(fileRU[i].get(indexes[i]).getDateDepart() < fileRU[selectedIndex].get(indexes[selectedIndex]).getDateDepart())
						selectedIndex = i;
				}
			}
			selectedPlacement = fileRU[selectedIndex].get(indexes[selectedIndex]);
			
			// On compte le nombre de taches et de ressources distribuees rencontrees
			nbResDed[selectedPlacement.getRessourceDedie()]++;
			nbSousTch[selectedPlacement.getTache()]++;
			
			// On compare avec l'element suivant dans chaque file
			for(int i = 0 ; i<numRU && valid ; i++){
				if(i == selectedIndex){
					if(indexes[i] + 1 < fileRU[i].size()){
						// Non valide si la sous tache suivante commence avant la fin de la sous tache courante sur la meme ressource universelle
						if(selectedPlacement.getDateFin() > fileRU[i].get(indexes[i] + 1).getDateDepart()){
							valid = false;
							System.out.println("Invalide : " + selectedPlacement + " se termine apres le debut de " + fileRU[i].get(indexes[i] + 1));
						}
					}
				}
				else{
					if(indexes[i] < fileRU[i].size()){
						// Si intersection entre les deux sous taches
						if(selectedPlacement.getDateFin() > fileRU[i].get(indexes[i]).getDateDepart() && selectedPlacement.getDateDepart() < fileRU[i].get(indexes[i]).getDateFin()){
							/* Non valide si une sous tache qui s'execute en parallele sur une autre ressource universelle
							 * utilise la meme ressource dediee que la sous tache courante
							 */
							if(selectedPlacement.getRessourceDedie() == fileRU[i].get(indexes[i]).getRessourceDedie()){
								valid = false;
								System.out.println("Invalide : " + selectedPlacement + " et " + fileRU[i].get(indexes[i]) + " utilisent la meme ressource dediee et s'executent en meme temps");
							}
							/* Non valide si une sous tache qui s'execute en parallele sur une autre ressource universelle
							 * appartient a la meme tache que la sous tache courante
							 */
							if(selectedPlacement.getTache() == fileRU[i].get(indexes[i]).getTache()){
								valid = false;
								System.out.println("Invalide : " + selectedPlacement + " et " + fileRU[i].get(indexes[i]) + " appartiennent a la meme tache et s'executent en meme temps");
							}
						}
					}
				}
			}
			
			// On incremente l'index de la file qui vient d'etre traitee
			indexes[selectedIndex]++;
		}
		// Fin boucle verification des contraintes //
		
		// Verifie qu'il y a bien numRD sous taches et numT ressoruces distribu�es utilis�es
		if(valid){
			for(int i = 0 ; i<numRD && valid ; i++){
				if(nbResDed[i] != numT){
					valid = false;
					System.out.println("Invalide : La ressource dediee " + i + " est utilisee " + nbResDed[i] + " fois au lieu de " + numT);
				}
			}
			for(int i = 0 ; i<numT && valid ; i++){
				if(nbSousTch[i] != numRD){
					valid = false;
					System.out.println("Invalide : La tache " + i + " est divisee en " + nbSousTch[i] + " sous taches au lieu de " + numRD);
				}
			}
		}
		
		return valid;
	}
	
	public Solution getSolution() {
		return solution;
	}
}
